package com.fantastic.code;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author : fantastic
 * @date : 2024/6/21 11:03
 * @desc : this class for xxxxx
 **/
public class SeqPrint {

    static final int MAX_NUM = 100;
    static int number = 1;

    static final Object lock = new Object();
    static final ReentrantLock R_LOCK = new ReentrantLock();


    public static void main(String[] args) {
//        Thread oddThread = new Thread(new OddPrinter());
//        Thread evenThread = new Thread(new EvenPrinter());
//        oddThread.start();
//        evenThread.start();

//        Thread thread1 = new Thread(new Printer(0));
//        Thread thread2 = new Thread(new Printer(1));
//        Thread thread3 = new Thread(new Printer(2));
//        thread1.start();
//        thread2.start();
//        thread3.start();

        List<Condition> conditions = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            Condition condition = R_LOCK.newCondition();
            conditions.add(condition);
            Thread thread = new Thread(new PrinterWork(i, conditions));
            thread.start();
        }

    }


    static class OddPrinter implements Runnable {
        @Override
        public void run() {
            while (number <= MAX_NUM) {
                synchronized (lock) {
                    if (number % 2 == 0) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    } else {
                        System.out.println(number + ":" + Thread.currentThread().getName());
                        number++;
                        lock.notify();
                    }
                }


            }
        }
    }

    static class EvenPrinter implements Runnable {
        @Override
        public void run() {
            while (number <= MAX_NUM) {
                synchronized (lock) {
                    if (number % 2 != 0) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    } else {
                        System.out.println(number + ":" + Thread.currentThread().getName());
                        number++;
                        lock.notify();
                    }
                }
            }
        }
    }

    static class Printer implements Runnable {

        private Integer index;

        public Printer(Integer index) {
            this.index = index;
        }

        @Override
        public void run() {
            while (number <= MAX_NUM) {
                synchronized (lock) {
                    try {
                        while (number % 3 != index) {
                            lock.wait();
                        }
                        if (number <= MAX_NUM) {
                            System.out.println(number + ":" + Thread.currentThread().getName());
                        }
                        number++;
                        lock.notifyAll();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }


    static class PrinterWork implements Runnable {

        private Integer index;
        private List<Condition> conditions;

        public PrinterWork(Integer index, List<Condition> conditions) {
            this.index = index;
            this.conditions = conditions;
        }

        private void signalNext() {
            int nextIndex = (index + 1) % conditions.size();
            conditions.get(nextIndex).signal();
        }

        @Override
        public void run() {
            while (true) {
                R_LOCK.lock();
                try {
                    if (number % 3 != index) {
                        //不符合条件则等待
                        conditions.get(index).await();
                    }
                    if (number > 100) {
                        signalNext();
                        return;
                    }
                    //打印
                    System.out.println(number + ":" + Thread.currentThread().getName());
                    //数据+1
                    number++;
                    //唤醒下一个线程
                    signalNext();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    R_LOCK.unlock();
                }

            }
        }
    }
}
